/**
 * Copyright 2011 Honeywell Federal Manufacturing & Technologies, LLC. This material was produced under U.S. Government
 * contract DE-ACO4-01AL66850, Honeywell Federal Manufacturing & Technologies, LLC, (FM&T) with the U. S. Department of
 * Energy for the operation of the Kansas City Plant . The U.S. Government has rights to use, reproduce, and distribute
 * this software.  NEITHER THE GOVERNMENT NOR Honeywell Federal Manufacturing & Technologies, LLC, MAKES ANY WARRANTY,
 * EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE.  If software is modified to produce
 * derivative works, such modified software should be clearly marked, so as not to confuse it with the version available
 * from FM&T.
 *
 * Additionally, this program is free software; you can redistribute it and/or modify it under the terms of the GNU
 * General Public License Version 3 published by the Free Software Foundation. Accordingly, this program is distributed in
 * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this library.
 * If not, see http://www.gnu.org/licenses/.
 */
package org.braintrain.tapestry.services;

import com.kcp.ko.fmtnmlib.collection.CollectionUtils;
import com.kcp.ko.fmtnmlib.csv.AbstractIteratableDataSource;
import com.kcp.ko.fmtnmlib.csv.CSVDataSource;
import com.kcp.ko.fmtnmlib.csv.CSVWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.PageRedirectException;
import org.apache.tapestry.util.ContentType;
import org.apache.tapestry.web.WebResponse;
import org.braintrain.domain.EvaluationData;
import org.braintrain.domain.Module;

import javax.activation.MimetypesFileTypeMap;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.util.Iterator;
import java.util.Set;

/**
 * The Tapestry Service for building and hosting the Evaluation CSV files for a
 * given Module.
 * 
 * @author John Ericksen
 * @author Robert H. Engelhardt
 * 
 */
public class EvaluationCSVService extends BrainTrainEngineServiceAdapter {

    private static final Logger LOG = Logger.getLogger(EvaluationCSVService.class);

	public static final String SERVICE_NAME = "evaluationCSVService";
	public static final String FILE_NAME = "evaluations.csv";
	public static final String MODULE_ID = "moduleId";

	private MimetypesFileTypeMap mimeTypes = new MimetypesFileTypeMap();

	private static final Log log = LogFactory.getLog(TestAnswerLogCSVService.class); // define log

	/*
	 * (non-Javadoc)
	 * @see org.apache.tapestry.engine.IEngineService#getName()
	 */
	public String getName() {
		return SERVICE_NAME;
	}

	/*
	 * (non-Javadoc)
	 * @see org.apache.tapestry.engine.IEngineService#service(org.apache.tapestry.IRequestCycle)
	 */
	public void service(IRequestCycle cycle) throws IOException {

		if (!getBraintrainVisit().getAuthenticatedUser().hasBasicAccess()) {
			throw new PageRedirectException("NotAuthorized");
		}

		log.info(getBraintrainVisit().getAuthenticatedUser().getProfile().getName().toString() + " retrieved file via " + SERVICE_NAME); // log event

		Long moduleId = unsqueezeParameter(cycle, Long.class, MODULE_ID);
		Module module = getHibernateSearchService().getById(Module.class, moduleId);
		Set<EvaluationData> evaluations = module.getEvaluations();

		WebResponse response = cycle.getInfrastructure().getResponse();
		response.setHeader("Content-disposition", "attachment; filename=" + FILE_NAME);
		response.setHeader("Cache-Control", "max-age=0");
		OutputStream out = response.getOutputStream(new ContentType(mimeTypes.getContentType(FILE_NAME)));

		CSVDataSource datasource = new EvaluationDataDatasource(evaluations.iterator());

		CSVWriter.writeCSV(datasource, out); // render CSV data
		out.flush();

	}

	/*
	 * CSV Data source for the answer logs
	 * 
	 * @author Robert H. Engelhardt
	 */
	public static class EvaluationDataDatasource extends AbstractIteratableDataSource<EvaluationData> {

		private static final long serialVersionUID = 1255111340577329760L;

		/**
		 * Construct a new EvaluationDataDatasource
		 * @param evaluationDataIterator the iterator to a collection of EvealuationData
		 */
		public EvaluationDataDatasource(final Iterator<EvaluationData> evaluationDataIterator) {
			setRecordIterator(evaluationDataIterator);
		}

		/*
		 * (non-Javadoc)
		 * @see com.kcp.ko.fmtnmlib.csv.CSVDataSource#columnCount()
		 */
		public int columnCount() {
			return EvaluationDataColumn.values().length;
		}

		/*
		 * (non-Javadoc)
		 * @see com.kcp.ko.fmtnmlib.csv.CSVDataSource#getColumnHeading(int)
		 */
		public String getColumnHeading(int index) {
			return EvaluationDataColumn.values()[index].getHeading();
		}

		/*
		 * (non-Javadoc)
		 * @see com.kcp.ko.fmtnmlib.csv.CSVDataSource#getFieldValue(int)
		 */
		public String getFieldValue(int index) {
			return EvaluationDataColumn.values()[index].getColumnValue(getCursor());
		}

		/*
		 * (non-Javadoc)
		 * @see com.kcp.ko.fmtnmlib.csv.CSVDataSource#initialize()
		 */
		public void initialize() {
			// nothing to do here
		}
	}
	
    /**
     * Column definition for EvaluationData output
     * @author Robert H. Engelhardt
     *
     */
    public static enum EvaluationDataColumn {
    	
    	DATE("Date") {
			public String getColumnValue(final EvaluationData cursor) {
				DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT);
				return cursor.getEvalDate() != null ? format.format(cursor.getEvalDate()) : "";
			}
    	},
    	MODULE("Module Name") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getModule().getNullSafeName().getRelevantValue(false);
			}
    	},
    	BACKGROUND("Responsibilities") {
			public String getColumnValue(final EvaluationData cursor) {
				try {
					return CollectionUtils.implodeBeanCollection(cursor.getBackground(), "background");
				} catch (InvocationTargetException e) {
                    LOG.error("Error constructing background concatination", e);
                } catch (NoSuchMethodException e) {
                    LOG.error("Error constructing background concatination", e);
                } catch (IllegalAccessException e) {
                    LOG.error("Error constructing background concatination", e);
                }
                return "";
            }
    	},
    	KNOWLEDGELEVEL("Knowledge Level") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getKnowledgeLevel().getName();
			}
    	},
    	EXPECTATIONS("Met Expectations") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getExpectations().getName();
			}
    	},
    	QUALITY("Quality Rating") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getQuality().getName();
			}
    	},
    	AMOUNT("Amount of Information") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getAmount().getName();
			}
    	},
    	JOBHELP("Help Job") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getJobHelp().getName();
			}
    	},
    	USERFRIENDLY("User Friendly") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getUserFriendly().getName();
			}
    	},
    	REACTION("Overall Reaction") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getReaction().getName();
			}
    	},
    	USEFULLESSON("Which lesson will be the most useful to you on your job?") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getUsefulLesson();
			}
    	},
    	MODULEDROP("What do think should be dropped from this module?") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getModuleDrop();
			}
    	},
    	MODULEADD("What do you think should be added to this module?") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getModuleAdd();
			}
    	},
    	LIKELEAST("What did you like least?") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getLikeLeast();
			}
    	},
    	LIKEMOST("What did you like most?") {
			public String getColumnValue(final EvaluationData cursor) {
				return cursor.getLikeMost();
			}
    	};
    	
    	private final String heading;
    	
    	/**
    	 * Construct a new EvaluationDataColumn
    	 * @param heading the column heading string
    	 */
    	private EvaluationDataColumn(final String heading) {
    		this.heading = heading;
    	}
    	
    	/**
    	 * @return the title of the column
    	 */
    	public String getHeading(){
    		return heading;
    	}

    	/**
    	 * Get the column value based on the row cursor
    	 * @param cursor the current cursor
    	 * @return the column value based on the given cursor
    	 */
    	public abstract String getColumnValue(final EvaluationData cursor);
    	
    }

}
